
package com.cloud.quickcommon.utils;

import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Objects;

/**
 * jdk8 LocaDateTime 工具类
 *
 * @author NiJo_H
 */
abstract class TimeUtils {

    private final static DateTimeFormatter DF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private final static DateTimeFormatter NO_SYMBOL = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    private final static DateTimeFormatter NO_SYMBOL2 = DateTimeFormatter.ofPattern("yyyyMMdd");
    private final static DateTimeFormatter DF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    private final static DateTimeFormatter DF3 = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    /**
     * 格式化为 yyyy-MM-dd HH:mm:ss
     */
    public static String formatDateTime(LocalDateTime dateTime) {
        if (dateTime == null) {
            return "";
        }
        return DF.format(dateTime);
    }

    /**
     * 格式化为 yyyyMMddHHmmss
     */
    public static String formatDateTime2NoSymbol(LocalDateTime dateTime) {
        if (dateTime == null) {
            return "";
        }
        return NO_SYMBOL.format(dateTime);
    }

    /**
     * yyyy-MM-dd HH:mm:ss 变 LocalDateTime
     */
    public static LocalDateTime parseDateTime(String dateTime) {
        if (StringUtils.hasText(dateTime)) {
            try {
                return DF.parse(dateTime, LocalDateTime::from);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    /**
     * yyyy-MM-dd HH:mm 变 LocalDateTime
     */
    public static LocalDateTime parseDateTimeNoSecond(String dateTime) {
        if (StringUtils.hasText(dateTime)) {
            try {
                return DF2.parse(dateTime, LocalDateTime::from);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    /**
     * yyyyMMddHHmmss 变 LocalDateTime
     */
    public static LocalDateTime parseDateTimeNoSymbol(String dateTime) {
        if (StringUtils.hasText(dateTime)) {
            try {
                return NO_SYMBOL.parse(dateTime, LocalDateTime::from);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    /**
     * yyyyMMdd 变 LocalDate
     */
    public static LocalDate parseDateNoSymbol(String dateTime) {
        if (StringUtils.hasText(dateTime)) {
            try {
                return NO_SYMBOL2.parse(dateTime, LocalDate::from);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    /**
     * yyyy-MM-dd 变 LocalDate
     */
    public static LocalDate parseDateNoLocalDate(String dateTime) {
        if (StringUtils.hasText(dateTime)) {
            try {
                return DF3.parse(dateTime, LocalDate::from);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }


    /**
     * 计算两个日期之间的间隔时间 不强制要求时间的先后顺序
     *
     * @param from 开始日期
     * @param to   结束日期
     * @return 时间间隔(小时数)
     */
    public static int betweenDay(LocalDate from, LocalDate to) {
        if (from.isEqual(to)) {
            return 0;
        }
        if (to.isAfter(from)) {
            return Integer.parseInt(String.valueOf(from.until(to, ChronoUnit.DAYS)));
        } else {
            return Integer.parseInt(String.valueOf(to.until(from, ChronoUnit.DAYS)));
        }
    }

    /**
     * 计算两个日期之间的间隔时间 不强制要求时间的先后顺序
     *
     * @param from 开始时间
     * @param to   结束时间
     * @return 时间间隔(分钟数), 不满一分钟不按一分钟计算
     */
    public static int between(LocalTime from, LocalTime to) {
        int minutes;
        if (to.isAfter(from)) {
            minutes = Integer.parseInt(String.valueOf(from.until(to, ChronoUnit.MINUTES)));
        } else {
            minutes = Integer.parseInt(String.valueOf(to.until(from, ChronoUnit.MINUTES)));
        }
        return minutes == 0 ? 1 : minutes;
    }

    /**
     * 计算两个日期之间的间隔时间 不强制要求时间的先后顺序
     *
     * @param from 开始时间
     * @param to   结束时间
     * @return 时间间隔(分钟数), 不满一分钟不按一分钟计算
     */
    public static int between(LocalDateTime from, LocalDateTime to) {
        int minutes;
        if (to.isAfter(from)) {
            minutes = Integer.parseInt(String.valueOf(from.until(to, ChronoUnit.MINUTES)));
        } else {
            minutes = Integer.parseInt(String.valueOf(to.until(from, ChronoUnit.MINUTES)));
        }
        return minutes == 0 ? 1 : minutes;
    }

    /**
     * 计算开始时间到结束时间的时间差
     *
     * @param from 开始时间
     * @param to   结束时间
     * @return x小时y分钟
     */
    public static String betweenHourMinutes(LocalDateTime from, LocalDateTime to) {
        long sec = from.until(to, ChronoUnit.SECONDS);
        long h = sec / 3600;
        long m = sec % 3600 / 60;
        return h + "小时" + m + "分钟";
    }

    /**
     * 字符串格式的时间戳转换为LocalDateTime类型的时间
     *
     * @param timestamp 字符串格式的时间戳
     * @return LocalDateTime类型的时间
     */
    public static LocalDateTime timestampToLocalDateTime(String timestamp) {
        Objects.requireNonNull(timestamp, "字符串的timestamp为空");
        LocalDateTime date = Instant.ofEpochMilli(Long.valueOf(timestamp)).atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        return date;
    }

    /**
     * Long类型的时间戳转换为LocalDateTime类型的时间
     *
     * @param timestamp Long类型的时间戳
     * @return LocalDateTime类型的时间
     */
    public static LocalDateTime timestampToLocalDateTime(Long timestamp) {
        Objects.requireNonNull(timestamp, "长整形的timestamp为空");
        LocalDateTime date = Instant.ofEpochMilli(Long.valueOf(timestamp)).atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        return date;
    }

    /**
     * LocalDateTime类型的时间转换为Long类型的时间戳
     *
     * @param ldt LocalDateTime类型的时间
     * @return long类型的时间戳
     */
    public static long localDateTimeToTimestamp(LocalDateTime ldt) {
        Objects.requireNonNull(ldt, "长整形的timestamp为空");
        long timestamp = ldt.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        return timestamp;
    }


    /**
     * 计算时间--当前日期操作
     */
    public static String countDateByNow(int time) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long addTime = time * 60 * 60 * 1000;
        Date afterDate = new Date(System.currentTimeMillis() + addTime);
        String format = sdf.format(afterDate);
        return format;
    }

    /**
     * 计算年龄now-出生日期
     *
     * @param YYYY-MM-dd
     */
    public static int countAgeByYears(String bridate) {
        long age = ChronoUnit.YEARS.between(parseDateNoLocalDate(bridate), LocalDate.now());
        return new Long(age).intValue();
    }

    /**
     * 获取当天最大时间
     */
    public static LocalDateTime getEndOfDay() {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(TimeUtils.localDateTimeToTimestamp(LocalDateTime.now())), ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return endOfDay.atZone(ZoneId.systemDefault()).toLocalDateTime();
    }
}
